package com.je.meta.service.project;

import com.alibaba.fastjson2.JSONObject;
import com.je.common.base.DynaBean;
import com.je.common.base.service.MetaService;
import com.je.common.base.spring.SpringContextHolder;
import com.je.common.base.util.SecurityUserHolder;
import com.je.common.base.util.TreeUtil;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.model.dd.DicInfoVo;
import com.je.meta.rpc.project.ProjectInfoRpcService;
import com.je.meta.rpc.project.ProjectLevelRpcService;
import com.je.meta.rpc.project.ProjectOrgRpcService;
import com.je.servicecomb.RpcSchemaFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 构建项目层级树
 */
@Service("projectLevelTreeService")
public class ProjectLevelTreeService {

    @Autowired
    private MetaService metaService;

    public JSONTreeNode buildTree(DicInfoVo dicInfoVo) {
        return abstractBuildTree(dicInfoVo, false);
    }

    private void recursiveLevelCode(JSONTreeNode parentNode, List<DynaBean> levelBeanList,
                                    String levelPkFieldCode, String levelCodeFieldCode,
                                    String levelNameFieldCode, String levelParentIdFieldCode, String nodeInfo) {
        JSONTreeNode levelTreeNode;
        for (DynaBean eachLevelBean : levelBeanList) {
            if (!parentNode.getId().equals(eachLevelBean.getStr(levelParentIdFieldCode))) {
                continue;
            }
            levelTreeNode = buildLevelTreeNode(eachLevelBean,
                    levelPkFieldCode, levelCodeFieldCode, levelNameFieldCode, levelParentIdFieldCode, nodeInfo);
            parentNode.getChildren().add(levelTreeNode);
            recursiveLevelCode(levelTreeNode, levelBeanList,
                    levelPkFieldCode, levelCodeFieldCode,
                    levelNameFieldCode, levelParentIdFieldCode, nodeInfo);
        }
    }

    private JSONTreeNode buildLevelTreeNode(DynaBean levelBean, String levelPkFieldCode, String levelCodeFieldCode,
                                            String levelNameFieldCode, String levelParentIdFieldCode, String nodeInfo) {
        JSONTreeNode levelTreeNode = TreeUtil.buildTreeNode(levelBean.getStr(levelPkFieldCode),
                levelBean.getStr(levelNameFieldCode),
                levelBean.getStr(levelCodeFieldCode),
                nodeInfo,
                "level_info",
                "fas fa-folder-open",
                levelBean.getStr(levelParentIdFieldCode));
        levelTreeNode.setBean(levelBean.getValues());
        return levelTreeNode;
    }

    private void recursiveAddProjectNode(JSONTreeNode node, List<DynaBean> projectBeanList, String infoPkFieldCode,
                                         String infoCodeFieldCode, String infoNameFieldCode,
                                         String infoLevelIdFieldCode, String nodeInfo, Map<String, List<JSONObject>> orgMap) {
        if ("level_info".equals(node.getNodeInfoType())) {
            for (DynaBean eachProjectBean : projectBeanList) {
                if (node.getId().equals(eachProjectBean.getStr(infoLevelIdFieldCode))) {
                    JSONTreeNode jsonTreeNode = buildProjectTreeNode(node, eachProjectBean, infoPkFieldCode, infoCodeFieldCode, infoNameFieldCode, nodeInfo, orgMap);
                    if (jsonTreeNode != null) {
                        node.getChildren().add(jsonTreeNode);
                    }
                }
            }
        }

        if (node.getChildren() == null || node.getChildren().isEmpty()) {
            return;
        }

        for (JSONTreeNode eachChildNode : node.getChildren()) {
            if (eachChildNode.getNodeInfoType().equals("project_org")) {
                continue;
            }
            recursiveAddProjectNode(eachChildNode, projectBeanList, infoPkFieldCode,
                    infoCodeFieldCode, infoNameFieldCode, infoLevelIdFieldCode, nodeInfo, orgMap);
        }

    }

    private JSONTreeNode buildProjectTreeNode(JSONTreeNode parentNode, DynaBean projectBean, String infoPkFieldCode,
                                              String infoCodeFieldCode, String infoNameFieldCode, String nodeInfo,
                                              Map<String, List<JSONObject>> orgMap) {
        if (!(orgMap != null && orgMap.size() > 0 && orgMap.containsKey(projectBean.getStr(infoPkFieldCode)))) {
            return null;
        }
        JSONTreeNode projectTreeNode = TreeUtil.buildTreeNode(projectBean.getStr(infoPkFieldCode),
                projectBean.getStr(infoNameFieldCode),
                projectBean.getStr(infoCodeFieldCode),
                nodeInfo,
                "project_info",
                "fas fa-layer-group",
                parentNode.getId());
        projectTreeNode.setBean(projectBean.getValues());
        if (orgMap != null && orgMap.get(projectBean.getStr(infoPkFieldCode)) != null && orgMap.get(projectBean.getStr(infoPkFieldCode)).size() > 0) {
            List<JSONObject> list = orgMap.get(projectBean.getStr(infoPkFieldCode));
            for (JSONObject jsonObject : list) {
                JSONTreeNode orgTreeNode = TreeUtil.buildTreeNode(jsonObject.getString("id"),
                        jsonObject.getString("text"),
                        jsonObject.getString("code"),
                        nodeInfo,
                        "project_org",
                        "fas fa-file",
                        parentNode.getId());

                Map<String, Object> orgBean = ((DynaBean) jsonObject.get("bean")).getValues();
                orgBean.put("projectId", projectTreeNode.getId());
                orgBean.put("projectName", projectTreeNode.getText());
                orgBean.put("projectCode", projectTreeNode.getCode());
                orgTreeNode.setBean(orgBean);
                projectTreeNode.getChildren().add(orgTreeNode);
            }
        }
        return projectTreeNode;
    }

    private JSONTreeNode abstractBuildTree(DicInfoVo dicInfoVo, boolean loadOrg) {
        String nodeInfo = dicInfoVo.getFieldCode();
        JSONTreeNode root = TreeUtil.buildRootNode();

        DynaBean levelMappingBean = metaService.selectOne("JE_RBAC_PROJECTLEVELMAPPING",
                ConditionsWrapper.builder().eq("PROJECTLEVELMAPPING_ENABLE_CODE", "1"));
        if (levelMappingBean == null) {
            return root;
        }

        String levelProduct = levelMappingBean.getStr("PROJECTLEVELMAPPING_PRODUCT_CODE");
        String tableCode = levelMappingBean.getStr("PROJECTLEVELMAPPING_TABLE_CODE");
        String levelPkFieldCode = levelMappingBean.getStr("PROJECTLEVELMAPPING_PKFIELD_CODE");
        String levelCodeFieldCode = levelMappingBean.getStr("PROJECTLEVELMAPPING_CODEFIELD_CODE");
        String levelNameFieldCode = levelMappingBean.getStr("PROJECTLEVELMAPPING_NAMEFIELD_CODE");
        String levelOrderFieldCode = levelMappingBean.getStr("PROJECTLEVELMAPPING_ORDERFIELD_CODE");
        String levelParentIdFieldCode = levelMappingBean.getStr("PROJECTLEVELMAPPING_PARENTFIELD_CODE");
        String levelGlSql = levelMappingBean.getStr("PROJECTLEVELMAPPING_GLSQL");
        if (levelProduct == null) {
            return root;
        }

        ProjectLevelRpcService projectLevelRpcService;
        if ("meta".equals(levelProduct)) {
            projectLevelRpcService = SpringContextHolder.getBean(ProjectLevelRpcService.class);
        } else {
            projectLevelRpcService = RpcSchemaFactory.getRemoteProvierClazz(levelProduct, "projectLevelRpcService", ProjectLevelRpcService.class);
        }

        List<DynaBean> levelBeanList = projectLevelRpcService.findAllWithOrder(tableCode, levelOrderFieldCode, levelGlSql);
        if (levelBeanList == null || levelBeanList.isEmpty()) {
            return root;
        }


        Map<String, List<JSONObject>> orgMap = new HashMap<>();
        if (loadOrg) {
            ProjectOrgRpcService projectOrgRpcService;
            DynaBean userMappingBean = metaService.selectOne("JE_RBAC_PROJECTUSERMAPPING",
                    ConditionsWrapper.builder().eq("PROJECTUSERMAPPING_ENABLE_CODE", "1"));
            String userProductCode = userMappingBean.getStr("PROJECTUSERMAPPING_PRODUCT_CODE");
            if ("meta".equals(userProductCode)) {
                projectOrgRpcService = SpringContextHolder.getBean(ProjectOrgRpcService.class);
            } else {
                projectOrgRpcService = RpcSchemaFactory.getRemoteProvierClazz(userProductCode, "projectOrgRpcService", ProjectOrgRpcService.class);
            }

            String userTable = userMappingBean.getStr("PROJECTUSERMAPPING_TABLE_CODE");
            String userGlSql = userMappingBean.getStr("PROJECTUSERMAPPING_GLSQL");
            String accDeptId = SecurityUserHolder.getCurrentAccount().getDeptId();
            String accDeptUserIdFiledCode = userMappingBean.getStr("PROJECTUSERMAPPING_SYSUSERPKFIELD_CODE");
            String userOrgIdFiled = userMappingBean.getStr("PROJECTUSERMAPPING_DEPTIDFIELD_CODE");
            DynaBean orgMappingBean = metaService.selectOne("JE_RBAC_PROJECTORGMAPPING",
                    ConditionsWrapper.builder().eq("PROJECTORGMAPPING_ENABLE_CODE", "1"));
            String orgTable = orgMappingBean.getStr("PROJECTORGMAPPING_TABLE_CODE");
            String orgGlSql = orgMappingBean.getStr("PROJECTORGMAPPING_GLSQL");
            String orgTablePkField = orgMappingBean.getStr("PROJECTORGMAPPING_PKFIELD_CODE");
            String orgfProjectKey = orgMappingBean.getStr("PROJECTORGMAPPING_PROJECTPKFIELD_CODE");
            String orgNameFiled = orgMappingBean.getStr("PROJECTORGMAPPING_NAMEFIELD_CODE");
            String orgCodeFiled = orgMappingBean.getStr("PROJECTORGMAPPING_CODEFIELD_CODE");
            String orgOrderByCodeFiled = orgMappingBean.getStr("PROJECTORGMAPPING_ORDERFIELD_CODE");
            List<DynaBean> orgBeans = projectOrgRpcService.findProjectInformationPersonnel(userTable, accDeptId, accDeptUserIdFiledCode, userOrgIdFiled,
                    orgTable, orgTablePkField, orgOrderByCodeFiled, userGlSql, orgGlSql);
            for (DynaBean dynaBean : orgBeans) {
                String projectId = dynaBean.getStr(orgfProjectKey);
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("id", dynaBean.getStr(orgTablePkField));
                jsonObject.put("text", dynaBean.getStr(orgNameFiled));
                jsonObject.put("code", dynaBean.getStr(orgCodeFiled));
                jsonObject.put("bean", dynaBean);
                if (orgMap.get(projectId) == null) {
                    List<JSONObject> list = new ArrayList<>();
                    list.add(jsonObject);
                    orgMap.put(projectId, list);
                } else {
                    orgMap.get(projectId).add(jsonObject);
                }
            }
        }


        JSONTreeNode eachRootLevelNode;
        for (DynaBean eachLevelBean : levelBeanList) {
            if (!"ROOT".equals(eachLevelBean.get(levelParentIdFieldCode))) {
                continue;
            }
            eachRootLevelNode = buildLevelTreeNode(eachLevelBean, levelPkFieldCode, levelCodeFieldCode, levelNameFieldCode, levelParentIdFieldCode, nodeInfo);
            root.getChildren().add(eachRootLevelNode);
        }

        for (int i = 0; i < root.getChildren().size(); i++) {
            recursiveLevelCode(root.getChildren().get(i), levelBeanList,
                    levelPkFieldCode, levelCodeFieldCode, levelNameFieldCode, levelParentIdFieldCode, nodeInfo);
        }

        DynaBean projectMappingBean = metaService.selectOne("JE_RBAC_PROJECTMAPPING",
                ConditionsWrapper.builder().eq("PROJECTMAPPING_ENABLE_CODE", "1"));
        if (levelMappingBean == null) {
            return root;
        }

        String infoProduct = projectMappingBean.getStr("PROJECTMAPPING_PRODUCT_CODE");
        String infoTableCode = projectMappingBean.getStr("PROJECTMAPPING_TABLE_CODE");
        String infoPkFieldCode = projectMappingBean.getStr("PROJECTMAPPING_PKFIELD_CODE");
        String infoNameFieldCode = projectMappingBean.getStr("PROJECTMAPPING_NAMEFIELD_CODE");
        String infoCodeFieldCode = projectMappingBean.getStr("PROJECTMAPPING_CODEFIELD_CODE");
        String infoLevelIdFieldCode = projectMappingBean.getStr("PROJECTMAPPING_LEVELFIELD_CODE");
        String infoLevelGlSql = projectMappingBean.getStr("PROJECTMAPPING_GLSQL");

        ProjectInfoRpcService projectInfoRpcService;
        if ("meta".equals(infoProduct)) {
            projectInfoRpcService = SpringContextHolder.getBean(ProjectInfoRpcService.class);
        } else {
            projectInfoRpcService = RpcSchemaFactory.getRemoteProvierClazz(infoProduct, "projectInfoRpcService", ProjectInfoRpcService.class);
        }

        List<DynaBean> projectBeanList = projectInfoRpcService.findAllWithOrder(infoTableCode, infoLevelGlSql);
        if (projectBeanList == null || projectBeanList.isEmpty()) {
            return root;
        }

        //根据deptid获取所拥用的部门信息，放到项目下面
        if (loadOrg) {
            recursiveAddProjectNode(root, projectBeanList, infoPkFieldCode,
                    infoCodeFieldCode, infoNameFieldCode, infoLevelIdFieldCode, nodeInfo, orgMap);
            filterNodes(root);
        } else {
            recursiveAddProjectNode(root, projectBeanList, infoPkFieldCode,
                    infoCodeFieldCode, infoNameFieldCode, infoLevelIdFieldCode, nodeInfo, null);
        }
        return root;
    }

    /**
     * 移除子节点及其后代中不包含 "project_org" 类型的节点。
     * @param root 根节点
     */
    public void filterNodes(JSONTreeNode root) {
        if (root == null) {
            return;
        }
        // 遍历子节点
        Iterator<JSONTreeNode> iterator = root.getChildren().iterator();
        while (iterator.hasNext()) {
            JSONTreeNode child = iterator.next();
            // 如果子节点及其后代中不包含 "project_org"，移除该子节点
            if (!containsProjectOrg(child)) {
                iterator.remove();
            } else {
                // 递归检查子节点
                filterNodes(child);
            }
        }
    }

    /**
     * 判断当前节点及其后代是否包含类型为 "project_org" 的节点。
     * @param node 当前节点
     * @return 如果包含返回 true，否则返回 false
     */
    private boolean containsProjectOrg(JSONTreeNode node) {
        // 当前节点是否为 "project_org"
        if ("project_org".equals(node.getNodeInfoType())) {
            return true;
        }
        // 递归检查子节点
        for (JSONTreeNode child : node.getChildren()) {
            if (containsProjectOrg(child)) {
                return true;
            }
        }
        return false;
    }



    public JSONTreeNode buildSwchTree(DicInfoVo dicInfoVo) {
        return abstractBuildTree(dicInfoVo, true);
    }


}
